package com.ww.springboot.boot.thread.study.base.lock.aqs;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

@Slf4j
class Mutex implements Lock {
    // 静态内部类，自定义同步器
    private static class Sync extends AbstractQueuedSynchronizer {
        // 是否处于占用状态
        protected boolean isHeldExclusively() {
            return getState() == 1;
        }

        /**
         * 获取锁
         * 1.state为0时 标识锁释放
         * 2.compareAndSetState抢到锁 则将当前锁线程赋值
         * 3.如果资源被锁 则判断是否是当前线程占用 是则获取锁 否则返回false
         * @param acquires
         * @return
         */
        public boolean tryAcquire(int acquires) {
            //比较并复制 原子操作
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                if (compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }

        // 释放锁，将状态设置为0
        protected boolean tryRelease(int releases) {
            if (getState() == 0) throw new
                    IllegalMonitorStateException();
            setExclusiveOwnerThread(null);
            setState(0);
            return true;
        }

        // 返回一个Condition，每个condition都包含了一个condition队列
        Condition newCondition() {
            return new ConditionObject();
        }
    }

    // 仅需要将操作代理到Sync上即可
    private final Sync sync = new Sync();

    public void lock() {
        //获取锁
        //log.debug(Thread.currentThread() + "获取锁");
        sync.acquire(1);
    }

    public boolean tryLock() {
        //尝试获取锁
        //log.debug(Thread.currentThread() + "尝试获取锁");
        return sync.tryAcquire(1);
    }

    public void unlock() {
        //解锁
        //log.debug(Thread.currentThread() + "解锁");
        sync.release(1);
    }

    public Condition newCondition() {
        //创建Condition
        log.debug(Thread.currentThread() + "创建Condition");
        return sync.newCondition();
    }

    public boolean isLocked() {
        //是否锁暂用
        //log.debug(Thread.currentThread() + "是否锁暂用");
        return sync.isHeldExclusively();
    }

    public boolean hasQueuedThreads() {
        //队列中是否有线程等待
        //log.debug(Thread.currentThread() + "队列中是否有线程等待");
        return sync.hasQueuedThreads();
    }

    public int getState() {
        //队列中是否有线程等待
        //log.debug(Thread.currentThread() + "队列中是否有线程等待");
        return getState();
    }

    public void lockInterruptibly() throws InterruptedException {
        //锁中断
        log.debug(Thread.currentThread() + "锁中断");
        sync.acquireInterruptibly(1);
    }

    public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException {
        //尝试获取锁--指定时间内
        log.debug(Thread.currentThread() + "尝试获取锁--指定时间内");
        return sync.tryAcquireNanos(1, unit.toNanos(timeout));
    }
}